#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
Created on 21 jun 2011

@author: Joakim Lindskog

Copyright (c) 2011 Joakim Lindskog

This file is part of MyGarden.

    MyGarden is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MyGarden is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MyGarden.  If not, see <http://www.gnu.org/licenses/>.
'''
import game, util, events
from util import config
from gardenbase import gardensprite
from cocos import euclid
from plants import plant

class Bed(gardensprite.GardenSprite):
    '''
    A framed bed for growing plants in
    '''
    # Starting values
    START_WATER = 50.0
    START_NUTRIENTS = 150.0
    BASE_COLOUR = 240, 240, 240
    
    # Images
    bed_image = None
    soil_image = None
    grass_image = None
    water_image = None
    
    # Sow sound
    sow_sound = None
    
    def __init__(self):
        '''
        Constructor
        '''
        
        # Load images if not already loaded
        if not Bed.bed_image:
            Bed.bed_image = util.load_image('bed.png')
            Bed.soil_image = util.load_image('earth.png')
            Bed.grass_image = util.load_image('grass.png')
            Bed.water_image = util.load_image('puddles.png')
            
        # Load sound if not already loaded
        if not Bed.sow_sound:
            Bed.sow_sound = util.load_effect('mark.ogg')
            
        # Call super constructor with frame image
        super(Bed, self).__init__(Bed.bed_image)
        
        # Add earth image
        self.soil = gardensprite.GardenSprite(Bed.soil_image)
        self.soil.image_anchor = 0,0
        self.soil.position = 6, 13
        self.add(self.soil, 1)
        
        # Add grass layer
        self.grass_layer = gardensprite.GardenSprite(Bed.grass_image)
        self.grass_layer.image_anchor = 0,0
        self.grass_layer.position = 6, 13
        self.grass_layer.opacity = 0
        self.add(self.grass_layer, 2)
        
        # Add water layer
        self.water_layer = gardensprite.GardenSprite(Bed.water_image)
        self.water_layer.image_anchor = 0,0
        self.water_layer.position = 6, 13
        self.water_layer.opacity = 0
        self.add(self.water_layer, 3)
        
        self.resetValues()
        
    def addPlant(self, plant, z=5):
        '''
        Adds a plant to this bed
        
        @param plant: the plant to add
        @type plant: Plant
        
        @param z: the z-value of the plant
        @param z: int
        ''' 
        self.plants.append(plant)
        plant.z = z
        self.add(plant, z)
        # Play sound effect
        Bed.sow_sound.play()
        # Dispatch event
        events.EventBus().dispatch_event(events.BedClickEvent(self))
        
    def update(self, dt):
        '''
        Updates this bed
        
        @param dt: delta-time, number of seconds since last update
        @type dt: float
        '''
        # Update temperature
        self.temperature = game.Game().temperature
        # Update plants
        for plant in self.plants:
            plant.grow(self, game.Game(), dt)
        # Update water amount (water lost to evaporation and sift-through)
        self.water -= ((1.17**self.temperature)*dt*0.01\
            +((self.water-74.5)*dt if self.water > 74.5 else 0.1*dt)\
            -((1.15**self.grass)*dt*0.01)) if self.water > 0 else 0
        if self.water < 0: self.water = 0
        # Update grass amount (convert to nutrients)
        self.nutrients += self.grass/(10+(self.nutrients/33)**3)*dt # Nutrients flow out if there is too much
        self.grass -= (self.temperature/30)*dt if self.grass > 0 else 0
        # Update grass layer opacity
        self.grass_layer.opacity = self.grass*10 if self.grass < 25.5 else 255
        if self.grass_layer.opacity < 0: self.grass_layer.opacity = 0
        # Update water layer opacity
        if self.water > 74.5:
            if self.water < 100:
                self.water_layer.opacity = (self.water-74.5)*10
            else:
                self.water_layer.opacity = 255
        else:
            self.water_layer.opacity = 0
        # Update soil layer colour based on available nutrients
        self.soil.color = Bed.BASE_COLOUR[0]-self.nutrients*0.7,\
                          Bed.BASE_COLOUR[1]-self.nutrients*0.75,\
                          Bed.BASE_COLOUR[2]-self.nutrients*0.9
            
    def on_mouse_press(self, x, y, button, modifiers):
        # Check if harvest tool is used
        if game.Game().selected_tool == game.Game().gui_layer.menu.harvest_tool:
            # Check if a plant is clicked
            hits = self._get_hit_items(x, y, self.plants)
            pick = self._get_closest_item(hits)
            if pick:
                game.Game().selected_tool.use(self, x, y, button, modifiers)
                self.harvest(pick)
                return True
            else: return False
        # Check if soil was clicked (with a negative margin to avoid frame clicks)
        elif self.soil.is_clicked(x, y, button, modifiers, -52, -7):
            tool = game.Game().selected_tool
            if tool != None:
                tool.use(self, x, y, button, modifiers)
                return True
            elif self.soil.is_clicked(x, y, button, modifiers, -120, -20):
                seed = game.Game().selected_seed
                if(seed != None):
                    plant = game.Game().selected_seed()
                    local = self.point_to_local(euclid.Vector2(x, y))
                    self.addPlant(plant, z=100-local.y)
                    plant.position = local.x, local.y
                    return True
    
    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if not self.soil.is_clicked(x, y, button, modifiers, -52, -7):
            tool = game.Game().selected_tool
            if tool != None and tool.target == self:
                tool.cancel()
                return True
        return False
    
    def on_mouse_motion(self, x, y, dx, dy):
        # Check if the mouse is hovering over a plant in this bed
        # and you're using the harvest tool
        if game.Game().selected_tool != game.Game().gui_layer.menu.harvest_tool:
            return False
        hits = self._get_hit_items(x, y, self.plants)
        pick = self._get_closest_item(hits)
        if pick:
            if pick != self.hover:
                pick.selected = True
                pick.y += plant.Plant.HOVER_HEIGHT
                if self.hover != None:
                    self.hover.selected = False
                    self.hover.y -= plant.Plant.HOVER_HEIGHT
                self.hover = pick
            return True
        else:
            if self.hover != None:
                self.hover.selected = False
                self.hover.y -= plant.Plant.HOVER_HEIGHT
                self.hover = None
            return False
    
    def harvest(self, plant):
        '''
        Harvests the supplied plant
        
        @param plant: the plant to harvest
        @type plant: Plant
        '''
        self.plants.remove(plant)
        game.Game().harvest(plant)
        
    def _get_hit_items(self, x, y, list):
        '''
        Returns the hit items
        
        @param x: the x-coordinate to test
        @type x: float
        
        @param y: the y-coordinate to test
        @type y: float
        
        @param list: the list of items to test against
        @type list: list
        
        @return: the hit items
        @rtype: list
        '''
        hits = []
        for item in list:
            local = self.point_to_local(euclid.Vector2(x, y))
            if local.x > item.x-item.image_anchor_x*item.scale\
                and local.x < item.x-item.image_anchor_x*item.scale+item.width\
                and local.y > item.y-item.image_anchor_y*item.scale\
                and local.y < item.y-item.image_anchor_y*item.scale+item.height:
                hits.append(item)
        return hits
    
    def _get_closest_item(self, list):
        '''
        Returns the closest item in the list
        (closest to front)
        
        @param list: the list to check against
        @type list: list
        
        @return: the closest item
        @rtype: Plant
        '''
        if len(list) > 0:
            high_z = 0
            pick = None
            for item in list:
                if item.z > high_z:
                    high_z = item.z
                    pick = item
            return pick
        else: return None
        
    def resetValues(self):
        '''
        Resets the bed to start values
        '''
        # Amount of moisture in the bed
        self.water = Bed.START_WATER
        # Nutrient levels in the bed (general)
        self.nutrients = Bed.START_NUTRIENTS
        # Bed temperature, in degrees Celcius
        self.temperature = config.AVERAGE_SOIL_TEMPS[game.Game().month];
        
        # Amount of grass on bed
        self.grass = 0.0
        
        # Set colour of earth based on water in bed
        self.soil.color = Bed.BASE_COLOUR[0]-self.nutrients*0.7,\
                          Bed.BASE_COLOUR[1]-self.nutrients*0.75,\
                          Bed.BASE_COLOUR[2]-self.nutrients*0.9
        
        self.plants = []
        
        # Hover check for plants
        self.hover = None
    
    def resetBed(self):
        '''
        Resets the bed
        '''
        for plant in self.plants:
            plant.kill()
        self.resetValues()